using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class StateManager {
	private static StateManager instance = null;
	
	public static void DestroyInstance ()
	{
		if (instance == null)
		{
			return;
		}
		
		instance.Destroy();
		instance = null;
	}
	
	public static void InitiateInstance ()
	{
		DestroyInstance();
		instance = new StateManager();
	}
	
	public static StateManager Instance
	{
		get
		{
			return instance;
		}
	}

	//State steps should allow for undoing event actions. Even in the case of an error, the local data can be easily reverted to a previous state.
	//This also allows previous states to potentially be read for comparison to the current state.
	private List<Dictionary<string,StateDataContainer>> stateSteps = new List<Dictionary<string,StateDataContainer>>();

	private bool readOnly = false;
	
	public StateManager ()
	{

	}
	
	public void Destroy ()
	{

	}

	//Concatenates all of the state steps in the given range.
	public void ConcatStateSteps (int index , int count)
	{
		List<Dictionary<string,StateDataContainer>> stateStepsRange = stateSteps.GetRange(index , count);
		int i = stateStepsRange.Count - 1;

		if (i < 0)
		{
			return;
		}

		Dictionary<string,StateDataContainer> stateStepLast = stateStepsRange[i];
		for (i-- ; i >= 0 ; i--)
		{
			Dictionary<string,StateDataContainer> stateStepTarget = stateStepsRange[i];
			foreach (KeyValuePair<string,StateDataContainer> pair in stateStepLast)
			{
				if (stateStepTarget.ContainsKey(pair.Key))
				{
					stateStepTarget.Remove(pair.Key);
				}

				StateDataContainer state = pair.Value;
				if (state != null)
				{
					state.ReadOnly = true;
					stateStepTarget.Add(pair.Key , state);
				}
			}
			stateStepLast = stateStepTarget;
		}

		stateSteps.RemoveRange(index , count);
		stateSteps.Insert(index , stateStepLast);
	}

	public void StartNewStateStep ()
	{
		if (ReadOnly)
		{
			Debug.LogError("Cannot start a new state step while ReadyOnly has a value of '" + ReadOnly + "'.");
			return;
		}

		if (stateSteps.Count > 0)
		{
			int index = stateSteps.Count - 1;
			Dictionary<string,StateDataContainer> stateStepLast = stateSteps[index];
			if (stateStepLast.Count == 0)
			{
				//If no data was recorded to the last state step, there is no reason to add a new one.
				return;
			}
		}

		Dictionary<string,StateDataContainer> stateStepNew = new Dictionary<string,StateDataContainer>();
		stateSteps.Add(stateStepNew);
	}

	public StateDataContainer GetState (string stateId , bool writable)
	{
		int stepLastIndex = stateSteps.Count - 1;
		for (int i = stepLastIndex ; i >= 0 ; i--)
		{
			Dictionary<string,StateDataContainer> stateStep = stateSteps[i];
			if (!stateStep.ContainsKey(stateId))
			{
				continue;
			}

			StateDataContainer state = stateStep[stateId];
			if (writable && i != stepLastIndex)
			{
				state = (StateDataContainer)state.CloneWritable();
			}
			return state;
		}
		return null;
	}

	public bool SetState (StateDataContainer state)
	{
		if (ReadOnly)
		{
			Debug.LogError("Cannot set a state while ReadOnly is set to '" + ReadOnly + "'.");
			return false;
		}

		if (state == null)
		{
			Debug.LogError("Cannot set a null state.");
			return false;
		}

		if (state.ReadOnly)
		{
			Debug.LogError("Cannot add state with ReadOnly set to true.");
			return false;
		}

		int i = stateSteps.Count - 1;
		if (i < 0)
		{
			Debug.LogError("Cannot add state. There are no state steps.");
			return false;
		}

		Dictionary<string,StateDataContainer> stateStepLast = stateSteps[i];

		if (stateStepLast.ContainsKey(state.StateId))
		{
			stateStepLast.Remove(state.StateId);
		}

		if (i != 0)
		{
			state.ReadOnly = true;
			stateStepLast.Add(state.StateId , state);
		}
		return true;
	}

	public bool RemoveState (string stateId)
	{
		if (ReadOnly)
		{
			Debug.LogError("Cannot remove a state while ReadOnly is set to '" + ReadOnly + "'.");
			return false;
		}

		int i = stateSteps.Count - 1;
		if (i < 0)
		{
			Debug.LogError("Cannot add state. There are no state steps.");
			return false;
		}
		
		Dictionary<string,StateDataContainer> stateStepLast = stateSteps[i];
		
		if (stateStepLast.ContainsKey(stateId))
		{
			stateStepLast.Remove(stateId);
		}
		
		if (i != 0)
		{
			stateStepLast.Add(stateId , null);
		}
		return true;
	}

	public bool ReadOnly
	{
		get
		{
			return readOnly;
		}
		set
		{
			readOnly = value;
		}
	}
}
